<?php

namespace app\common\controller;

use app\common\validate\BaseValidate;
use app\user\model\User;

use think\facade\Request;
use think\exception\ValidateException;
/**
 * Created by PhpStorm.
 * User: snuz
 * Date: 2020/7/7
 * Time: 14:49
 */
class BaseController
{
    // 请求参数 变量
    public $request;
    // 用户变量
    public $user;
    public $field = 'id,avatarurl,nickname as nickName,phone,binding_time,invite_id,invite_code,is_fictitious,is_proceeds,level,remarks,last_time,add_time,openid,session_key';
    public $token;
    public $mid;
    public $apiSerect = 'kajsbkd123b55kwbdkj128y87';
    public $redis;
    // 默认验证错误 抛出并结束 为 false  则返回错误字符串
    public $errorValidate = True;
    // 默认批量验证  默认情况下，一旦有某个数据的验证规则不符合，就会停止后续数据及规则的验证，如果希望批量进行验证
    public $batchValidate = False;
    // 默认验证器-场景值 没有
    public $sceneValidate = '';
    // 请求参数数据
    public $v_params = null;

    // 构造函数， 调用就是开启验证 token，并返回用户信息
    public function __construct()
    {
        $app = app();
        if(isset($app->user)) $this->user = $app->user;
        $this->request = Request();
        /*if($bool){
           if($this->getToken()){
               return True;
           }
           return retu_json(400,'token失效或者不存在');
       }*/
    }


    //是 否有token且有该用户名
    public function getToken($bool = False){
        $userModel = new User();
        $token = input('server.HTTP_AUTHORIZATION');
        if(!$token)
            return False;
        if($token && $this->user = $userModel->where('token',$token)->find()){
            // 如果时间在两天内符合
            if($this->user->last_time > 0 &&  time() - $this->user->last_time <= 24 * 3600 * 7){
                // 是否更新时间
                if($bool){
                    $this->user->last_time = time();
                    $this->user->save();
                }
                return True;
            }
            return False;
        }else{
            $redis = getRedis();
            $userId = $redis->get('token:'.$token);
            if($userId && $userId > 0){
                if($this->user = $userModel->where('id',$userId)->find()){
                    return True;
                }
                return False;
            }
        }
        return False;
    }

    /*
     * 判断是否是游客
     */
    public function checkeUser()
    {
        if(empty($this->user)) return false;
        return $this->user->phone ? true : false;
    }

    /**
     * @desc 校验token的有效性
     */
    public  function checkToken(){
        $redis = getRedis();
        $key = "token:".$this->token;
        $mid = $redis->get($key);
        if(!$mid){
            return ['msg'=>'token已过期或不合法，请重新登录！'];
        }
        $this->mid = $mid;
        return true;
    }

    /**
     * @desc 校验签名
     */
    private function checkSign(){
        $sign = Request::param('sign');
        if(empty($sign)){
            return ['msg'=>'sign为空！'];
        }
        $timestamp = Request::param('timestamp');
        if($timestamp < time()-120){
            return ['msg'=>'签名已超时！'];
        }
        $postParams = Request::except(['path_url']);
        //$postParams = input('post.');
        if(empty($postParams)){
            $postParams['timestamp'] = $timestamp;
        }else unset($postParams['sign']);
        $params = [];
        ksort($postParams);
        foreach($postParams as $k=>$v) {
            $params[] = sprintf("%s%s", $k,$v);
        }
        $apiSerect = $this->apiSerect;
        $str = sprintf("%s%s%s", $apiSerect, implode('', $params), $apiSerect);
        if ( md5($str) != $sign ) {
            return ['msg'=>'签名校验失败！'];
        }else return true;
    }

    /**
     * @desc nonce校验预防接口重放
     */
    private function checkNonce(){
        $sign = input('post.sign');
        if(empty($sign)){
            return ['msg'=>'sign为空'];
        }
        $nonce = input('post.nonce');
        if(empty($nonce)){
            return ['msg'=>'nonce为空'];
        }
        $nonceKey = sprintf("sign:%s:nonce:%s", $sign, $nonce);
        $redis = getRedis();
        $nonV = $redis->get($nonceKey);
        if ( !empty($nonV)) {
            return ['msg'=>'请勿重复调用'];
        } else {
            $redis->set($nonceKey,$nonce,360);
            return true;
        }
    }


    /**
     * 获取请求参数 并设置默认值操作
     * @param $key 传递过来需要读取的字符串 和 默认的值
     */
    public function getSetDefaultParams($key,$data = [])
    {
        $bool = count($data) > 0;
        if(!$bool && !$this->v_params)
            $this->v_params = $this->request->param();
        return getSetDefaultValueKeyArrs($bool ? $data : $this->v_params,$key);
    }

    /**
     * 验证器----使用  需要自定义验证规则
     * @param $class 验证器类
     * @param array $arr 需要验证的数据，不传拿取的为默认的请求数据
     * @param string $scene 验证器场景
     * @return array|bool|string|void
     */
    public function checkValidate($class,Array $arr = [],String $scene = '')
    {
        try {
            $arrLen = count($arr);
            if(!$this->v_params && $arrLen == 0)
                $this->v_params = $this->request->param();
            return validate($class)
                ->scene($scene ? $scene : $this->sceneValidate)
                ->batch($this->batchValidate)
                ->check(!$arr || $arrLen == 0 ? $this->v_params : $arr);
        } catch (ValidateException $e) {
            if($this->errorValidate)
                return retu_json(400,$e->getError());
            return $e->getError();
        }
    }

    /**
     * 动态验证器
     * @param array $arr 验证数据
     * @param array $rule 验证器规则
     * @param String $scene 验证器场景
     * @return array|bool|string|\think\bool|void 返回的类型 true  表示 ok
     */
    public function ruleValidate(Array $rule = [],Array $arr = [],String $scene = '')
    {
        if(!$rule || count($rule) == 0 && isset($this->defaultRule))
            $rule = $this->defaultRule;
        if(!$rule)
            return false;
        try{
            $arrLen = count($arr);
            if(!$this->v_params && $arrLen == 0)
                $this->v_params = $this->request->param();
            return validate(BaseValidate::class)->rule($rule)->scene($scene)->batch($this->batchValidate)
                ->check(!$arr || $arrLen == 0 ? $this->v_params : $arr);
        } catch (ValidateException $e) {
            if($this->errorValidate)
                return retu_json(400,$e->getError());
            return $e->getError();
        }
    }

    // 验证此操作函数是否需要登录才可以进行操作
    public function checkLogin($arrs){
        $actions = strtolower(\think\facade\Request::action(true));
        if(empty($this->user)&&!in_array($actions,$arrs))
            return retu_json(402, '请先登录！', [$actions,$arrs]);
    }
}